package com.eastfair.venueservice.service.impl;

import cn.hutool.core.bean.BeanUtil;
import cn.hutool.core.util.StrUtil;
//import com.baomidou.dynamic.datasource.annotation.DS;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.eastfair.boot.request.PageParams;
import com.eastfair.boot.service.SuperServiceImpl;
import com.eastfair.constant.BusinessConstant;
import com.eastfair.core.base.R;
import com.eastfair.core.context.ContextUtil;
import com.eastfair.venueservice.dao.ServiceLossMapper;
import com.eastfair.venueservice.dto.ServiceBorrowReturnDTO;
import com.eastfair.venueservice.dto.ServiceInventoryInFlowDTO;
import com.eastfair.venueservice.dto.ServiceLossDTO;
import com.eastfair.venueservice.entity.ServiceLoss;
import com.eastfair.venueservice.enumeration.*;
import com.eastfair.venueservice.service.ServiceInventoryInFlowService;
import com.eastfair.venueservice.service.ServiceLossService;
import com.eastfair.venueservice.vo.ServiceLossVO;
import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import javax.annotation.Resource;
import java.math.BigDecimal;
import java.time.LocalDate;
import java.util.*;
import java.util.function.BinaryOperator;
import java.util.function.Function;

/**
 * <p>
 * 业务实现类
 * 报损记录
 * </p>
 *
 * @author linan
 * @date 2022-09-19
 */
@Slf4j
@Service
//@DS("#thread.tenant")
public class ServiceLossServiceImpl extends SuperServiceImpl<ServiceLossMapper, ServiceLoss> implements ServiceLossService {

    @Resource
    private ServiceLossMapper serviceLossMapper;

    @Resource
    private ServiceInventoryInFlowService serviceInventoryInFlowService;

    /**
     * 处理逻辑删除相关处理
     *
     * @param modelList 实体
     * @return 是否成功
     */
    @Override
    protected R<Boolean> handlerRemoveByIdsOfLogic(Collection<ServiceLoss> modelList) {
        modelList.forEach(s -> s.setIsDeleted(BusinessConstant.YES));
        return R.successDef();
    }

    @Override
    protected R<Boolean> handlerSave(ServiceLoss model) {
        model.setProjectId(ContextUtil.getProjectId());
        model.setSubsystemId(ContextUtil.getSubSystemId());
        model.setReworkState(ServiceLossReworkStateEnum.NO);
        model.setLossTime(LocalDate.now());
        return R.successDef();
    }

    @Override
    public Page<ServiceLossVO> listServiceLossVO(PageParams<ServiceLossDTO> pageParams) {
        log.info("listServiceLossVO - 分页查询报损记录VO列表, pageParams={}", pageParams);
        Page<ServiceLoss> pageParam = pageParams.buildPage();
        ServiceLossDTO query = pageParams.getModel();
        QueryWrapper<ServiceLoss> queryWrapper = createServiceLossVOQueryWrapper(query);
        return serviceLossMapper.listServiceLossVO(pageParam, queryWrapper);
    }

    @Override
    public List<ServiceLoss> listServiceLoss(ServiceLossDTO serviceLossDTO) {
        QueryWrapper<ServiceLoss> queryWrapper = new QueryWrapper<>();
        queryWrapper
                .lambda()
                .eq(ServiceLoss::getIsDeleted, BusinessConstant.DELETE_NO)
                .eq(StrUtil.isNotBlank(serviceLossDTO.getInventoryCode()), ServiceLoss::getInventoryCode, serviceLossDTO.getInventoryCode())
        ;
        return list(queryWrapper);
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public boolean saveServiceLoss(ServiceLossDTO serviceLossDTO) {
        log.info("saveServiceLoss - 保存报损记录, serviceLossDTO={}", serviceLossDTO);
        ServiceLoss serviceLoss = BeanUtil.toBean(serviceLossDTO, ServiceLoss.class);
        return save(serviceLoss);
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public boolean updateServiceLoss(ServiceLossDTO serviceLossDTO) {
        log.info("updateServiceLoss - 更新报损记录, serviceLossDTO={}", serviceLossDTO);
        ServiceLoss serviceLoss = BeanUtil.toBean(serviceLossDTO, ServiceLoss.class);
        return updateById(serviceLoss);
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public boolean returnServiceLoss(ServiceBorrowReturnDTO serviceBorrowReturnDTO) {
        log.info("returnServiceLoss - 归还报损, serviceBorrowReturnDTO={}", serviceBorrowReturnDTO);
        ServiceLossDTO serviceLossDTO = new ServiceLossDTO();
        serviceLossDTO.setInventoryCode(serviceBorrowReturnDTO.getInventoryCode());
        ServiceLossGoodsLossStateEnum serviceLossGoodsLossStateEnum
                = ServiceLossGoodsLossStateEnum.get(serviceBorrowReturnDTO.getGoodsLossState().getCode());
        serviceLossDTO.setGoodsLossState(serviceLossGoodsLossStateEnum);
        serviceLossDTO.setLossNum(serviceBorrowReturnDTO.getBorrowNum());
        serviceLossDTO.setLossSource(ServiceLossLossSourceEnum.RETURN_SERVICE);
        serviceLossDTO.setLossOperator(serviceBorrowReturnDTO.getReturnOperator());
        serviceLossDTO.setLossOperatorName(serviceBorrowReturnDTO.getReturnOperatorName());
        return saveServiceLoss(serviceLossDTO);
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public boolean inventoryInFlowLoss(ServiceInventoryInFlowDTO serviceInventoryInFlowDTO) {
        log.info("inventoryInFlowLoss - 入库报损, serviceInventoryInFlowDTO={}", serviceInventoryInFlowDTO);
        ServiceLossDTO serviceLossDTO = new ServiceLossDTO();
        serviceLossDTO.setInventoryCode(serviceInventoryInFlowDTO.getInventoryCode());
        ServiceLossGoodsLossStateEnum serviceLossGoodsLossStateEnum
                = ServiceLossGoodsLossStateEnum.get(serviceInventoryInFlowDTO.getGoodsLossState().getCode());
        serviceLossDTO.setGoodsLossState(serviceLossGoodsLossStateEnum);
        serviceLossDTO.setLossNum(serviceInventoryInFlowDTO.getInNum());
        serviceLossDTO.setLossSource(ServiceLossLossSourceEnum.IN_INVENTORY);
        serviceLossDTO.setLossOperator(ContextUtil.getUserId());
        serviceLossDTO.setLossOperatorName(ContextUtil.getRealName());
        return saveServiceLoss(serviceLossDTO);
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public boolean repairInInventory(ServiceLossDTO serviceLossDTO) {
        log.info("repairInInventory - 返修入库, serviceLossDTO={}", serviceLossDTO);
        // 更新报损记录为已返修入库
        serviceLossDTO.setReworkState(ServiceLossReworkStateEnum.YES);
        serviceLossDTO.setRepairTime(LocalDate.now());
        updateServiceLoss(serviceLossDTO);
        // 保存入库
        ServiceInventoryInFlowDTO serviceInventoryInFlowDTO = new ServiceInventoryInFlowDTO();
        serviceInventoryInFlowDTO.setInventoryCode(serviceLossDTO.getInventoryCode());
        serviceInventoryInFlowDTO.setInNum(serviceLossDTO.getLossNum());
        serviceInventoryInFlowDTO.setInStockType(ServiceInventoryInFlowInStockTypeEnum.REPAIR);
        serviceInventoryInFlowDTO.setExhibitionManageId(serviceLossDTO.getExhibitionManageId());
        serviceInventoryInFlowDTO.setRemark(serviceLossDTO.getRemark());
        serviceInventoryInFlowDTO.setServiceProviderType(ServiceBorrowReturnGoodsLossStateEnum.UNDAMAGED.getCode());
        return serviceInventoryInFlowService.saveInFlow(serviceInventoryInFlowDTO);
    }

    @Override
    public Map<String, Object> countLossNumByGoodsLossState(ServiceLossDTO query) {
        log.info("countLossNumByGoodsLossState - 报损类型统计, query={}", query);
        QueryWrapper<ServiceLoss> queryWrapper = new QueryWrapper<>();
        queryWrapper
                .eq("sl.is_deleted", BusinessConstant.DELETE_NO)
                .eq(query.getExhibitionManageId() != null, "si.exhibition_manage_id", query.getExhibitionManageId())
                .eq(query.getServiceProviderId() != null, "si.service_provider_id", query.getServiceProviderId())
                .eq(StrUtil.isNotBlank(query.getServiceProviderType()), "si.service_provider_type", query.getServiceProviderType())
        ;
        List<Map<String, Object>> list = serviceLossMapper.countLossNumByGoodsLossState(queryWrapper);
        Optional<Double> totalOptional = list
                .stream()
                .map(map -> ((BigDecimal) map.get("value")).doubleValue())
                .reduce(Double::sum);
        Map<String, Object> map = new HashMap<>(16);
        map.put("data", list);
        map.put("total", totalOptional.orElse(0d));
        return map;
    }

    /**
     * 生成ServiceLossVO的查询
     *
     * @param query ServiceLossDTO
     * @return QueryWrapper
     */
    private QueryWrapper<ServiceLoss> createServiceLossVOQueryWrapper(ServiceLossDTO query) {
        QueryWrapper<ServiceLoss> queryWrapper = new QueryWrapper<>();
        queryWrapper
                .eq("sl.is_deleted", BusinessConstant.DELETE_NO)
                .eq(query.getExhibitionManageId() != null, "si.exhibition_manage_id", query.getExhibitionManageId())
                .eq(query.getServiceProviderId() != null, "si.service_provider_id", query.getServiceProviderId())
                .eq(StrUtil.isNotBlank(query.getServiceProviderType()), "si.service_provider_type", query.getServiceProviderType())
                .like(StrUtil.isNotBlank(query.getServiceName()), "si.service_name", query.getServiceName())
                .like(StrUtil.isNotBlank(query.getServiceSpecsName()), "sp.service_specs_name", query.getServiceSpecsName())
                .eq(query.getServiceCategoryId() != null, "siv.service_category_id", query.getServiceCategoryId())
                .eq(StrUtil.isNotBlank(query.getInventoryCode()), "siv.inventory_code", query.getInventoryCode())
                .eq(query.getGoodsLossState() != null, "sl.goods_loss_state", query.getGoodsLossState())
                .between(StrUtil.isNotBlank(query.getLossStartTime()) && StrUtil.isNotBlank(query.getLossEndTime()),
                        "sl.create_time", query.getLossStartTime(), query.getLossEndTime())
                .orderByDesc("sl.create_time")
        ;
        return queryWrapper;
    }
}
